/* Copyright (C) 2011 clueless <clueless.mmopeon@gmail.com>
 *
 * This file is part of MMO Peon.
 *
 * MMO Peon is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * MMO Peon is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with MMO Peon.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "movement.h"
#include "objectmap.h"
#include "../logic.h"
#include <cmath>
#include <sstream>
#include "../log.h"
PlayerMovement::PlayerMovement(MemBase *baseObject)
{
    this->baseObject = baseObject;
    isTurning = false;
    isMoving = false;
}

bool PlayerMovement::IsBusy() const
{
    return isMoving || isTurning;
}

bool PlayerMovement::IsMoving() const
{
    return isMoving;
}

bool PlayerMovement::IsTurning() const
{
    return isTurning;
}

void PlayerMovement::Move(const RomCoords &coords)
{
    isMoving = true;
    this->target = coords;
    Update();
}

void PlayerMovement::Move(const RomCoords *coords)
{
    isMoving = true;
    this->target = *coords;
    Update();
}

void PlayerMovement::Turn(const RomCoords &coords)
{
    isTurning = true;
    isMoving = false;
    this->target = coords;
    Update();
}

void PlayerMovement::Turn(const RomCoords *coords)
{
    isTurning = true;
    isMoving = false;
    this->target = *coords;
    Update();
}

void PlayerMovement::Stop()
{
    SetFlags(Flags::Nothing);
    isTurning = false;
    isMoving = false;
}

void PlayerMovement::Update()
{
    if (baseObject == 0 || baseObject->player == 0)
        return;

    float angleDiff = AngleDiff();
    float distance = memBase->player->coords.Distance(target);

    if (isTurning || isMoving)
    {
        if (angleDiff > 5.0)
            SetFlags(Flags::Right);
        else if (angleDiff < -5.0)
            SetFlags(Flags::Left);
        else
        {
            isTurning = false;
            SetFlags(Flags::NoTurn);
        }
    }

    if (isMoving)
    {
        if (distance > 80.0 && ::fabs(angleDiff) < 80.0)
            SetFlags(Flags::Forward);
        else if (distance > 5.0 && ::fabs(angleDiff) < 10.0)
            SetFlags(Flags::Forward);
        else if (distance <= 5.0)
        {
            isMoving = false;
            isTurning = false;
            SetFlags(Flags::NoRun);
            SetFlags(Flags::NoTurn);
        }
    }
}

void PlayerMovement::SetFlags(PlayerMovement::Flags action)
{
    uint8_t newMovement = memBase->movementFlag;

    switch(action)
    {
        case Flags::Forward:
        case Flags::Backward:
            newMovement &= Flags::NoRun;
            newMovement |= action;
            break;
        case Flags::Right:
        case Flags::Left:
            newMovement &= Flags::NoTurn;
            newMovement |= action;
            break;
        case Flags::RStrafe:
        case Flags::LStrafe:
            newMovement &= Flags::NoStrafe;
            newMovement |= action;
            break;
        case Flags::NoRun:
        case Flags::NoTurn:
        case Flags::NoStrafe:
        case Flags::Nothing:
            newMovement &= action;
            break;
    }

    memBase->movementFlag = newMovement;
}

float PlayerMovement::AngleDiff()
{
    float source = baseObject->player->vectors.Angle();
    float target = baseObject->player->coords.Angle(this->target);
    float result = target - source;
    if (result < -180.0)
        result += 360.0;
    else if (result > 180.0)
        result -= 360;

    return result;
}
